package com.yeban.bams.server.serversocket;

import com.yeban.bams.entity.Account;
import com.yeban.bams.server.manager.LoginManager;
import com.yeban.bams.server.log.BankImplByCglib;
import com.yeban.bams.server.log.LogAction;
import com.yeban.bams.server.log.LogManager;
import com.yeban.bams.service.Bank;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;

/**
 * @Desc 处理单个客户端请求的线程
 * @Author yeban
 * @Date 2025/11/7
 *
 *       ServerTasker "业务员"
 *       1. 读取ATMClient客户端发过来的对象
 *       2. 解析指令，发起Bank业务的逻辑
 *       3. 写回业务
 */
public class ServerTasker implements Runnable {

    private Socket socket;
    private Bank bank = Bank.getInstance();

    public ServerTasker(Socket socket) {
        this.socket = socket;
        bank = BankImplByCglib.wrap(bank);
    }

    @Override
    public void run() {
        try (
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());) {
            RequestTO request = (RequestTO) ois.readObject();
            System.out.println("收到客户端请求：" + request);
            if ("getAccountById".equals(request.getMethodName()) && request.getParams() != null
                    && request.getParams().length > 0) {
                System.out.println("刷新请求 - 账户ID: " + request.getParams()[0]);
            }

            // 显式登出：不进入 Bank 反射
            if ("logout".equals(request.getMethodName())) {
                Long accId = (Long) request.getParams()[0];
                LoginManager.logout(accId);
                oos.writeObject(new ResponseTO(true, null, "登出成功"));
                oos.flush();
                return;
            }

            // 2.使用反射调用Bank的对应方法
            Object result = null;
            boolean success = true;
            String message = "操作成功";
            try {
                // 获取方法对象
                Class<Bank> clazz = Bank.class;
                Method method = clazz.getDeclaredMethod(request.getMethodName(), request.getParamTypes());
                // 登录验证（账号唯一）
                if ("login".equals(request.getMethodName())) {
                    Long accId = (Long) request.getParams()[0];
                    if (!LoginManager.loginValid(socket, accId)) {
                        oos.writeObject(new ResponseTO(false, null, "该账户或IP已登录！"));
                        oos.flush();
                        return;
                    }
                }
                LogAction ann = method.getAnnotation(LogAction.class);
                if (ann != null && !BankImplByCglib.ACTIVE) {
                    String who = BankImplByCglib.resolveWho(request.getParams(), ann.whoArgIndex());
                    LogManager.addLog(who, ann.value());
                }
                result = method.invoke(bank, request.getParams());
                // 注册成功，登陆表记录
                if (("register".equals(method.getName())) && result instanceof Account) {
                    Account acc = (Account) result;
                    LoginManager.registerLogin(socket, acc.getId());
                }
            } catch (Exception e) {
                success = false;
                // 如果是 InvocationTargetException，提取原始异常
                Throwable cause = e;
                if (e instanceof java.lang.reflect.InvocationTargetException) {
                    Throwable originalCause = ((java.lang.reflect.InvocationTargetException) e).getCause();
                    if (originalCause != null) {
                        cause = originalCause;
                    }
                }
                message = "服务器执行出错：" + cause.getClass().getSimpleName() + " - " + cause.getMessage();
                cause.printStackTrace(); // 输出完整堆栈
            }

            // 3.构建响应对象
            ResponseTO response = new ResponseTO(success, result, message);
            // 4.返回结果给客户端
            oos.writeObject(response);
            System.out.println("已响应客户端请求：" + response);
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            // 仅关闭 socket；不再自动登出
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
